#include <string>
#include <list>
#include "node.h"
#include "declarationfunction.h"
#include "empty.h"

namespace AST {

    // Construtor
    DeclarationFunction::DeclarationFunction(std::string* identifier, Node* block, std::list<AST::Node*>* attributes, Node* type) {
        // Configurações
        this->_setIdentifier(identifier)
            ->_setBlock(block)
            ->_setAttributes(attributes)
            ->_setType(type);
    };

    // Construtor Simples
    DeclarationFunction::DeclarationFunction(std::string* identifier, Node* block) {
        // Configurações
        this->_setIdentifier(identifier)
            ->_setBlock(block);
    };

    // Construtor com Atributos e sem Retorno Tipado
    DeclarationFunction::DeclarationFunction(std::string* identifier, Node* block, std::list<AST::Node*>* attributes) {
        // Configurações
        this->_setIdentifier(identifier)
            ->_setBlock(block)
            ->_setAttributes(attributes);
    };

    // Construtor sem Atributos e com Retorno Tipado
    DeclarationFunction::DeclarationFunction(std::string* identifier, Node* block, Node* type) {
        // Configurações
        this->_setIdentifier(identifier)
            ->_setBlock(block)
            ->_setType(type);
    };

    // Configuração do Tipo de Retorno
    DeclarationFunction* DeclarationFunction::_setType(Node* type) {
        // Configuração
        this->_type = type;
        // Encadeamento
        return this;
    };

    // Configuração de Identificador
    DeclarationFunction* DeclarationFunction::_setIdentifier(std::string* identifier) {
        // Configuração
        this->_identifier = identifier;
        // Encadeamento
        return this;
    };

    // Configuração de Atributos
    DeclarationFunction* DeclarationFunction::_setAttributes(std::list<AST::Node*>* attributes) {
        // Configuração
        this->_attributes = attributes;
        // Encadeamento
        return this;
    };

    // Configuração de Bloco de Execução
    DeclarationFunction* DeclarationFunction::_setBlock(Node* block) {
        // Configuração
        this->_block = block;
        // Encadeamento
        return this;
    };

    // Apresentação de Tipagem de Retorno
    Node* DeclarationFunction::getType() {
        // Inicializado?
        if (this->_type == NULL) {
            // Inicialização de Vazio
            this->_setType(new Empty());
        }
        // Apresentação
        return this->_type;
    };

    // Apresentação de Identificador da Declaração
    std::string* DeclarationFunction::getIdentifier() {
        // Apresentação
        return this->_identifier;
    };

    // Apresentação do Conjunto de Atributos Definidos na Função
    std::list<AST::Node*>* DeclarationFunction::getAttributes() {
        // Inicializado?
        if (this->_attributes == NULL) {
            // Inicializar Atributos
            this->_setAttributes(new std::list<Node*>());
        }
        // Apresentação
        return this->_attributes;
    };

    // Apresentação do Bloco de Comandos
    Node* DeclarationFunction::getBlock() {
        // Apresentação
        return this->_block;
    };

    // Sobrescrita
    std::string DeclarationFunction::toString(int indent) {
        // Inicialização
        std::string output = this->getIndentSpaces(indent) +
            + "Function '" + (*this->getIdentifier()) + "'\n"
            + this->getIndentSpaces(indent + 1) + "Type\n"
                + this->getType()->toString(indent + 2) + "\n"
            + this->getIndentSpaces(indent + 1) + "Attributes";
        // Atributos
        std::list<Node*> attributes = (*this->getAttributes());
        for (std::list<Node*>::iterator i = attributes.begin(); i != attributes.end(); i++) {
            output = output + "\n" + (*i)->toString(indent + 2);
        }
        // Bloco
        output = output + "\n" + this->getBlock()->toString(indent + 1);
        // Apresentação
        return output;
    };

};
